package ltd.nullpointer.tcp.core.resolver;

import com.boot2.core.utils.ReflectUtil;
import io.netty.buffer.ByteBuf;
import javassist.CannotCompileException;
import javassist.NotFoundException;
import ltd.nullpointer.tcp.core.constant.TCPEnum;
import ltd.nullpointer.tcp.core.exception.MessageResolverException;
import ltd.nullpointer.tcp.core.message.AbstractTCPMessage;
import ltd.nullpointer.tcp.core.message.EncryDecryMessage;
import ltd.nullpointer.tcp.core.message.ErrorMessage;
import ltd.nullpointer.tcp.core.resolver.parser.ResolverParser;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;
import java.util.Map.Entry;

/**
 * @author zhangweilin
 * @ClassName: Message.java
 * @Description: 加密解密消息
 * @date 2018年1月18日 上午10:38:14
 */
public class MessageResolverFactory {
    private static Map<byte[], MessageResolver> messageAnalyzerMap = new HashMap<>();

    static {
        messageAnalyzerMap.put(EncryDecryMessage.KEY_HEADER_BYTE, new EncryDecryMessageResolver());
        messageAnalyzerMap.put(ErrorMessage.ERR_HEADER_BYTE, new ErrorMessageResolver());
        // messageAnalyzerMap.put(NPiotMessage.ARK_HEADER_BYTE, new
        // NPMessageAnalyzer());//由外部业务部分添加绑定
    }

    private MessageResolverFactory() {
    }

    public static final MessageResolverFactory getInstance() {
        return MessageResolverFactoryHolder.FACTORY;
    }

    /**
     * 构建各自协议的解析器
     * @param headerList  头
     * @param classFieldEntryMap
     * @param resolverParserMap
     * @throws CannotCompileException
     * @throws InstantiationException
     * @throws NotFoundException
     * @throws IllegalAccessException
     */
    public static void regResolvers(List<byte[]> headerList, Map<String, AbstractTCPMessageClassFieldEntry.ClassFieldEntry> classFieldEntryMap, Map<Class<?>, ResolverParser<?>> resolverParserMap) throws CannotCompileException, InstantiationException, NotFoundException, IllegalAccessException {
        if (CollectionUtils.isNotEmpty(headerList)) {
            for (int i = 0; i < headerList.size(); i++) {
                byte[] byteArr = headerList.get(i);
                buildAbstractTCPMessageResolver(classFieldEntryMap, resolverParserMap, byteArr);
            }
        }
    }

    /**
     * 构建各自协议的解析器
     * @param headerSet  头
     * @param classFieldEntryMap
     * @param resolverParserMap
     * @throws CannotCompileException
     * @throws InstantiationException
     * @throws NotFoundException
     * @throws IllegalAccessException
     */
    public static void regResolvers(Set<byte[]> headerSet, Map<String, AbstractTCPMessageClassFieldEntry.ClassFieldEntry> classFieldEntryMap, Map<Class<?>, ResolverParser<?>> resolverParserMap) throws CannotCompileException, InstantiationException, NotFoundException, IllegalAccessException {
        if (CollectionUtils.isNotEmpty(headerSet)) {
            for (byte[] byteArr : headerSet) {
                buildAbstractTCPMessageResolver(classFieldEntryMap, resolverParserMap, byteArr);
            }
        }
    }

    /**
     * 构建各自协议的解析器
     * @param classFieldEntryMap
     * @param resolverParserMap
     * @param byteArr
     * @throws NotFoundException
     * @throws CannotCompileException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private static void buildAbstractTCPMessageResolver(Map<String, AbstractTCPMessageClassFieldEntry.ClassFieldEntry> classFieldEntryMap, Map<Class<?>, ResolverParser<?>> resolverParserMap, byte[] byteArr) throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException {
        AbstractTCPMessageResolver abstractTCPMessageResolver = ReflectUtil.newProxyInstance(AbstractTCPMessageResolver.class);
        abstractTCPMessageResolver.setClassFieldEntryMap(classFieldEntryMap);
        abstractTCPMessageResolver.regResolverParserMap(resolverParserMap);
        abstractTCPMessageResolver.regHeader(byteArr);
        MessageResolverFactoryHolder.FACTORY.bindMessageAnalyzer(byteArr, abstractTCPMessageResolver);
    }

    /**
     * 外部可以注册自定义消息报文解析器
     *
     * @param header
     * @param messageAnalyzer
     */
    public void bindMessageAnalyzer(byte[] header, MessageResolver messageAnalyzer) {
        messageAnalyzerMap.put(header, messageAnalyzer);
    }

    /**
     * 解析字节
     *
     * @param byteBuf
     * @return
     */
    public AbstractTCPMessage resolve(ByteBuf byteBuf) {
        MessageResolver messageResolver = getResolver(byteBuf);
        if (null != messageResolver) {
            return messageResolver.resolver(byteBuf);
        }
        throw new MessageResolverException(TCPEnum.ErrorCode.err10002.getErrCode(), TCPEnum.ErrorCode.err10002.getName());
    }

    /**
     * 获取解析器
     *
     * @param byteBuf
     * @return
     */
    public MessageResolver getResolver(ByteBuf byteBuf) {
        if (!byteBuf.isReadable()) {
            return null;
        }
        Set<Entry<byte[], MessageResolver>> entrySet = messageAnalyzerMap.entrySet();
        for (Entry<byte[], MessageResolver> entry : entrySet) {
            byte[] header = entry.getKey();
            if (byteBuf.readableBytes() >= header.length) {
//                ByteBuf copy = byteBuf.retainedDuplicate();
                // 读取报文头
                final byte[] begin = new byte[header.length];
                byteBuf.readBytes(begin);
                byteBuf.resetReaderIndex();
                if (Arrays.equals(header, begin)) {
                    MessageResolver messageResolver = entry.getValue();
                    return messageResolver;
                }
            }
        }
        return null;
    }

    private static class MessageResolverFactoryHolder {
        private static final MessageResolverFactory FACTORY = new MessageResolverFactory();
    }

}
